# Always print this out before your assignment
sessionInfo()
getwd()
library('tidyverse')
-- Attaching packages ---------------------------------------------------------------------------------------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5     v purrr   0.3.4
v tibble  3.1.5     v stringr 1.4.0
v tidyr   1.1.4     v forcats 0.5.1
v readr   2.0.2     
-- Conflicts ------------------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x readr::col_factor() masks scales::col_factor()
x purrr::discard()    masks scales::discard()
x dplyr::filter()     masks stats::filter()
x dplyr::lag()        masks stats::lag()
library("fs")
library('here')
here() starts at C:/Users/cabrooke/Documents/R/696/group project/final project/final_project
library('dplyr')
library('tidyverse')
library('ggplot2')
library('ggrepel')
library('ggthemes')
library('forcats')
library('rsample')
library('lubridate')

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library('ggthemes')
library('kableExtra')

Attaching package: ‘kableExtra’

The following object is masked from ‘package:dplyr’:

    group_rows
library('pastecs')

Attaching package: ‘pastecs’

The following object is masked from ‘package:tidyr’:

    extract

The following objects are masked from ‘package:dplyr’:

    first, last
library('viridis')
Loading required package: viridisLite

Attaching package: ‘viridis’

The following object is masked from ‘package:scales’:

    viridis_pal
library('plotly')

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library('tidyquant')
Loading required package: PerformanceAnalytics
Loading required package: xts
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric


Attaching package: ‘xts’

The following objects are masked from ‘package:pastecs’:

    first, last

The following objects are masked from ‘package:dplyr’:

    first, last


Attaching package: ‘PerformanceAnalytics’

The following object is masked from ‘package:graphics’:

    legend

Loading required package: quantmod
Loading required package: TTR
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
== Need to Learn tidyquant? ===================================================================================================================================
Business Science offers a 1-hour course - Learning Lab #9: Performance Analysis & Portfolio Optimization with tidyquant!
</> Learn more at: https://university.business-science.io/p/learning-labs-pro </>
library('scales')

Final Project Cleaning and Summary Statistics

1a) Loading data


#Reading the data in and doing minor initial cleaning in the function call
#Reproducible data analysis should avoid all automatic string to factor conversions.
#strip.white removes white space 
#na.strings is a substitution so all that have "" will = na
data <- read.csv(here::here("final_project", "donor_data.csv"),
                 stringsAsFactors = FALSE,
                 strip.white = TRUE,
                 na.strings = "")

1b) Fixing the wonky DOB & Data cleanup

glimpse(data_cleaned$zipslry_range)
 logi [1:323000] NA NA NA NA NA NA ...

1c Creating factor variable for sex and married


data_cleaned <- 
  data_cleaned %>% 
  mutate(sex_fct = 
           fct_explicit_na(Sex)
  )


data_cleaned <-
data_cleaned %>% 
mutate(
  sex_simple = 
    fct_lump_n(Sex, n = 4)
)

#checking to see if its a factor
class(data_cleaned$sex_fct)

#checking levels
levels(data_cleaned$sex_simple)

#creating a table against Sex column 
table(data_cleaned$sex_fct, data_cleaned$sex_simple)

#making married a factor 
data_cleaned_columns <- 
  data_cleaned_columns %>% 
  mutate(married_fct = 
           fct_explicit_na(Married)
  )

#checking to see if its a factor
class(data_cleaned$married_fct)

1d #Mean, Median, and Count of Giving in Age Ranges


age_range_giving <- datacleaning %>%
  group_by(age_range) %>%
  summarise(avg_giving = mean(HH.Lifetime.Giving, na.rm = TRUE),
            med_giving = median(HH.Lifetime.Giving, na.rm = TRUE),
            amount_of_people_in_age_range = n())

Question 2

DonorSegment Analysis

#grouping by donorsegment and analyzing 
data_cleaned_columns %>%
  group_by(Donor.Segment) %>%
  summarise(Count = length(Donor.Segment),
            mean_total_giv = mean(HH.Lifetime.Giving)) %>%
  arrange(-Count) %>%
  filter(Count >= 100) %>%
  #added scales package to have the values show in dollar 
  mutate(mean_total_giv = dollar(mean_total_giv)) %>%
  kable(col.names = c("Donor Segment", "Count", "Mean HH Lifetime Giving"), align=rep('c', 3)) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = F)
Donor Segment Count Mean HH Lifetime Giving
NA 232033 $0
Lost Donor 69733 $4,958
Lapsed Donor 11220 $11,195
Current Donor 5704 $104,142
Lapsing Donor 3879 $16,595
At-Risk Donor 657 $85,198
NA
NA

2a) Plotting average giving by age range


ggplot(age_range_giving, aes(avg_giving, age_range)) +
  geom_bar(stat = "identity")

NA
NA

2b) Count of donors based on age range (another way to look at it)


ggplot(datacleaning, 
       aes(age_range)) + 
       geom_bar() + 
       theme(axis.text.x = element_text(angle=45,
                                        hjust=1)) + 
  labs(title = "Count of Age Ranges", x = "", y = "")

NA
NA

2c) Boxplot of the Age Ranges Against the Lifetime Giving Amounts with a log scale applied - the reason we applied log scale is to resolve issues with visualizations that skew towards large values in our dataset.


ggplot(datacleaning, aes(age_range,HH.Lifetime.Giving,fill = age_range)) + 
  geom_boxplot(
  outlier.colour = "red") + 
  scale_y_log10() +
  theme(axis.text.x=element_text(angle=45,hjust=1))
Warning: Transformation introduced infinite values in continuous y-axis
Warning: Removed 232033 rows containing non-finite values (stat_boxplot).

NA
NA

2d) Splitting by age and gender



#creating boxplots 
datacleaning %>% 
  filter(Age < 100) %>% #removing the weird outliers that are over 100 
  filter(Sex %in% c("M", "F")) %>%
  ggplot(aes(Sex, Age)) + 
  geom_boxplot() + 
  theme_economist() + 
  ggtitle("Ages of Donors Based on Gender") + 
  xlab(NULL) + ylab(NULL)

NA
NA
NA
NA
NA

2e) Distribution of people in the states that they live.


  datacleaning %>%
  mutate(State = ifelse(State == " ", "NA", State)) %>%
  filter(State != "NA") %>%
  group_by(State) %>%
  summarise(Count = length(State)) %>%
  filter(Count > 800) %>%
  arrange(-Count) %>%
  kable(col.names = c("Donor's State", "Count")) %>%
  kable_styling(bootstrap_options = c("condensed"),
                full_width = F)
Donor's State Count
CA 176695
WA 7958
TX 7268
NY 5661
CO 5073
AZ 4929
OR 4613
FL 4111
IL 3681
HI 3394
PA 2904
OH 2754
NV 2715
MI 2524
MA 2473
NJ 2311
VA 2158
NC 2087
GA 2045
MO 1889
MN 1732
MD 1488
TN 1443
IN 1417
CT 1380
WI 1330
UT 1174
OK 1151
AL 1120
LA 1110
ID 1096
SC 1076
KY 1032
KS 1027
NM 982
IA 880
NA
NA
NA
NA
NA
NA

2f) Looking at all donors first gift amount. 75% made a first gift of <100.


 no_non_donors <- datacleaning %>%
  filter(Lifetime.Giving != 0)
  
nd <- quantile(no_non_donors$HH.First.Gift.Amount, probs = c(.25,.50,.75,.9,.99), na.rm = TRUE)

nd <- as.data.frame(nd)

nd %>%
  kable(col.names = "Quantile") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = F)
Quantile
25% 3.8
50% 25.0
75% 100.0
90% 500.0
99% 15000.0
NA
NA
NA
NA

Modeling for you

3a) Linear model

#converting married Y and N to 1 and 0 
datacleaning <- datacleaning %>%
      mutate(Married_simple = ifelse(Married == "N",0,1))
 

mod1lm <- lm( Married_simple ~ Lifetime.Giving,
           data = datacleaning)

summary(mod1lm)

Call:
lm(formula = Married_simple ~ Lifetime.Giving, data = datacleaning)

Residuals:
    Min      1Q  Median      3Q     Max 
-0.4107 -0.2872 -0.2872  0.7128  0.7128 

Coefficients:
                      Estimate     Std. Error t value            Pr(>|t|)    
(Intercept)     0.287196453375 0.000796143577  360.73 <0.0000000000000002 ***
Lifetime.Giving 0.000000006818 0.000000007174    0.95               0.342    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4525 on 323224 degrees of freedom
Multiple R-squared:  2.795e-06, Adjusted R-squared:  -2.991e-07 
F-statistic: 0.9033 on 1 and 323224 DF,  p-value: 0.3419
  

Kmeans

is.numeric(data_cleaned$HH.Lifetime.Giving)
[1] TRUE

3a)

p <- datacleaning %>%
  ggplot(aes(Age)) + geom_histogram(bins=30, fill = "blue") + theme_economist_white() +
  ggtitle("Overall Donor Age Distribution") + 
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(5,100,by = 20)) +
  scale_y_continuous(breaks = seq(20,100,by = 20)) + xlim(c(20,100))
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
ggplotly(p)
Warning: Removed 199288 rows containing non-finite values (stat_bin).
  
p
Warning: Removed 199288 rows containing non-finite values (stat_bin).
Warning: Removed 2 rows containing missing values (geom_bar).

ggplot(data = datacleaning, aes(x = Age)) + geom_histogram(fill ="blue")+ xlim(c(20,100))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 199288 rows containing non-finite values (stat_bin).
Warning: Removed 2 rows containing missing values (geom_bar).

NA
NA
NA
LS0tDQp0aXRsZTogIkJST0NPREUgU3VtbWFyeSBTdGF0aXN0aWNzIg0KYXV0aG9yOiAiQWFyb24sIENhbm5vbiwgSm9zaCwgUnlhbiINCnN1YnRpdGxlOiBGaW5hbCBQcm9qZWN0IFN1bW1hcnkgU3RhdGlzdGljcw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoNCiMgUGxlYXNlIGxlYXZlIHRoaXMgY29kZSBjaHVuayBhcyBpcy4gSXQgbWFrZXMgc29tZSBzbGlnaHQgZm9ybWF0dGluZyBjaGFuZ2VzIHRvIGFsdGVyIHRoZSBvdXRwdXQgdG8gYmUgbW9yZSBhZXN0aGV0aWNhbGx5IHBsZWFzaW5nLiANCg0KbGlicmFyeShrbml0cikNCg0KDQojIENoYW5nZSB0aGUgbnVtYmVyIGluIHNldCBzZWVkIHRvIHlvdXIgb3duIGZhdm9yaXRlIG51bWJlcg0Kc2V0LnNlZWQoMTgxOCkNCm9wdGlvbnMod2lkdGg9NzApDQpvcHRpb25zKHNjaXBlbj05OSkNCg0KDQojIHRoaXMgc2V0cyB0ZXh0IG91dHB1dHRlZCBpbiBjb2RlIGNodW5rcyB0byBzbWFsbA0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGgud3JhcD01MCksdGlkeT1UUlVFLCBzaXplID0gInZzbWFsbCIpICANCm9wdHNfY2h1bmskc2V0KG1lc3NhZ2UgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICMgImNhY2hpbmciIHN0b3JlcyBvYmplY3RzIGluIGNvZGUgY2h1bmtzIGFuZCBvbmx5IHJld3JpdGVzIGlmIHlvdSBjaGFuZ2UgdGhpbmdzDQogICAgICAgICAgICAgICBjYWNoZSA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIyBhdXRvbWF0aWNhbGx5IGRvd25sb2FkcyBkZXBlbmRlbmN5IGZpbGVzDQogICAgICAgICAgICAgICBhdXRvZGVwID0gVFJVRSwNCiAgICAgICAgICAgICAgICMgDQogICAgICAgICAgICAgICBjYWNoZS5jb21tZW50cyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgIyANCiAgICAgICAgICAgICAgIGNvbGxhcHNlID0gVFJVRSwNCiAgICAgICAgICAgICAgICMgY2hhbmdlIGZpZy53aWR0aCBhbmQgZmlnLmhlaWdodCB0byBjaGFuZ2UgdGhlIGNvZGUgaGVpZ2h0IGFuZCB3aWR0aCBieSBkZWZhdWx0DQogICAgICAgICAgICAgICBmaWcud2lkdGggPSA1LjUsICANCiAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSA0LjUsDQogICAgICAgICAgICAgICBmaWcuYWxpZ249J2NlbnRlcicpDQoNCg0KYGBgDQoNCmBgYHtyIHNldHVwLTJ9DQoNCiMgQWx3YXlzIHByaW50IHRoaXMgb3V0IGJlZm9yZSB5b3VyIGFzc2lnbm1lbnQNCnNlc3Npb25JbmZvKCkNCmdldHdkKCkNCg0KYGBgDQoNCg0KPCEtLSAjIyMgc3RhcnQgYW5zd2VyaW5nIHlvdXIgcHJvYmxlbSBzZXQgaGVyZSAtLT4NCjwhLS0gWW91IG1heSBleHBvcnQgeW91ciBob21ld29yayBpbiBlaXRoZXIgaHRtbCBvciBwZGYsIHdpdGggdGhlIGZvcm1lciB1c3VhbGx5IGJlaW5nIGVhc2llci4gDQogICAgIFRvIGV4cG9ydCBvciBjb21waWxlIHlvdXIgUm1kIGZpbGU6IGNsaWNrIGFib3ZlIG9uICdLbml0JyB0aGVuICdLbml0IHRvIEhUTUwnIC0tPg0KPCEtLSBCZSBzdXJlIHRvIHN1Ym1pdCBib3RoIHlvdXIgLlJtZCBmaWxlIGFuZCB0aGUgY29tcGlsZWQgLmh0bWwgb3IgLnBkZiBmaWxlIGZvciBmdWxsIGNyZWRpdCAtLT4NCg0KDQpgYGB7ciBzZXR1cC0zfQ0KDQojIGxvYWQgYWxsIHlvdXIgbGlicmFyaWVzIGluIHRoaXMgY2h1bmsgDQpsaWJyYXJ5KCd0aWR5dmVyc2UnKQ0KbGlicmFyeSgiZnMiKQ0KbGlicmFyeSgnaGVyZScpDQpsaWJyYXJ5KCdkcGx5cicpDQpsaWJyYXJ5KCd0aWR5dmVyc2UnKQ0KbGlicmFyeSgnZ2dwbG90MicpDQpsaWJyYXJ5KCdnZ3JlcGVsJykNCmxpYnJhcnkoJ2dndGhlbWVzJykNCmxpYnJhcnkoJ2ZvcmNhdHMnKQ0KbGlicmFyeSgncnNhbXBsZScpDQpsaWJyYXJ5KCdsdWJyaWRhdGUnKQ0KbGlicmFyeSgnZ2d0aGVtZXMnKQ0KbGlicmFyeSgna2FibGVFeHRyYScpDQpsaWJyYXJ5KCdwYXN0ZWNzJykNCmxpYnJhcnkoJ3ZpcmlkaXMnKQ0KbGlicmFyeSgncGxvdGx5JykNCmxpYnJhcnkoJ3RpZHlxdWFudCcpDQpsaWJyYXJ5KCdzY2FsZXMnKQ0KDQoNCiMgbm90ZSwgZG8gbm90IHJ1biBpbnN0YWxsLnBhY2thZ2VzKCkgaW5zaWRlIGEgY29kZSBjaHVuay4gaW5zdGFsbCB0aGVtIGluIHRoZSBjb25zb2xlIG91dHNpZGUgb2YgYSBjb2RlIGNodW5rLiANCg0KYGBgDQoNCg0KDQojIyBGaW5hbCBQcm9qZWN0IENsZWFuaW5nIGFuZCBTdW1tYXJ5IFN0YXRpc3RpY3MgDQoNCjFhKSBMb2FkaW5nIGRhdGENCg0KYGBge3J9DQoNCiNSZWFkaW5nIHRoZSBkYXRhIGluIGFuZCBkb2luZyBtaW5vciBpbml0aWFsIGNsZWFuaW5nIGluIHRoZSBmdW5jdGlvbiBjYWxsDQojUmVwcm9kdWNpYmxlIGRhdGEgYW5hbHlzaXMgc2hvdWxkIGF2b2lkIGFsbCBhdXRvbWF0aWMgc3RyaW5nIHRvIGZhY3RvciBjb252ZXJzaW9ucy4NCiNzdHJpcC53aGl0ZSByZW1vdmVzIHdoaXRlIHNwYWNlIA0KI25hLnN0cmluZ3MgaXMgYSBzdWJzdGl0dXRpb24gc28gYWxsIHRoYXQgaGF2ZSAiIiB3aWxsID0gbmENCmRhdGEgPC0gcmVhZC5jc3YoaGVyZTo6aGVyZSgiZmluYWxfcHJvamVjdCIsICJkb25vcl9kYXRhLmNzdiIpLA0KICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgbmEuc3RyaW5ncyA9ICIiKQ0KDQpgYGANCg0KDQoxYikgRml4aW5nIHRoZSB3b25reSBET0IgJiBEYXRhIGNsZWFudXANCg0KYGBge3J9DQoNCiMoQmlydGhkYXRlIGFuZCBBZ2UsIElEIGFzIGEgbnVtYmVyKWFkZGluZyBET0IgKEFnZS9TcG91c2UgQWdlKSBpbiB5ZWFycyBjb2x1bW5zIGFuZCBhZGRpbmcgdHdvIGZpZWxkcyBmb3IgYXNzaWdubWVudCBhbmQgbnVtYmVyIG9mIGNoaWxkcmVuDQpkYXRhY2xlYW5pbmcgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKEJpcnRoZGF0ZSA9IGlmZWxzZShCaXJ0aGRhdGUgPT0gIjAwMDEtMDEtMDEiLCBOQSwgQmlydGhkYXRlKSkgJT4lDQogIG11dGF0ZShCaXJ0aGRhdGUgPSBtZHkoQmlydGhkYXRlKSkgJT4lDQogIG11dGF0ZShBZ2UgPSBhcy5udW1lcmljKGZsb29yKGludGVydmFsKHN0YXJ0PSBCaXJ0aGRhdGUsIGVuZD1TeXMuRGF0ZSgpKS9kdXJhdGlvbihuPTEsIHVuaXQ9InllYXJzIikpKSkgJT4lDQogIG11dGF0ZShTcG91c2UuQmlydGhkYXRlID0gaWZlbHNlKFNwb3VzZS5CaXJ0aGRhdGUgPT0gIjAwMDEtMDEtMDEiLCBOQSwgU3BvdXNlLkJpcnRoZGF0ZSkpICU+JQ0KICBtdXRhdGUoU3BvdXNlLkJpcnRoZGF0ZSA9IG1keShTcG91c2UuQmlydGhkYXRlKSkgJT4lDQogIG11dGF0ZShTcG91c2UuQWdlID0gYXMubnVtZXJpYyhmbG9vcihpbnRlcnZhbChzdGFydD0gU3BvdXNlLkJpcnRoZGF0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZD1TeXMuRGF0ZSgpKS9kdXJhdGlvbihuPTEsIHVuaXQ9InllYXJzIikpKSkgJT4lDQogIG11dGF0ZShJRCA9IGFzLm51bWVyaWMoSUQpKSAlPiUgDQogIG11dGF0ZShBc3NpZ25tZW50X2ZsYWcgPSBpZmVsc2UoaXMubmEoQXNzaWdubWVudC5OdW1iZXIpLCAwLDEpKSAlPiUgDQogIG11dGF0ZSggTm9fb2ZfQ2hpbGRyZW4gPSBpZmVsc2UoaXMubmEoQ2hpbGQuMS5JRCksMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoQ2hpbGQuMi5JRCksMSwyKSkpDQoNCiNzcGxpdHRpbmcgdXAgdGhlIGFnZSBpbnRvIHJhbmdlcyBhbmQgY3JlYXRpbmcgY2F0ZWdvcnkgZm9yIGVhc3kgdmlzdWFsaXphdGlvbiANCmRhdGFjbGVhbmluZyA8LSBkYXRhY2xlYW5pbmcgJT4lDQogIG11dGF0ZShhZ2VfcmFuZ2UgPSANCiAgICBpZmVsc2UoQWdlICVpbiUgMTA6MTksICIxMCA8IDIwIHllYXIgb2xkcyIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDIwOjI5LCAiMjAgPCAzMCB5ZWFyIG9sZHMiLCANCiAgICBpZmVsc2UoQWdlICVpbiUgMzA6MzksICIzMCA8IDQwIHllYXIgb2xkcyIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDQwOjQ5LCAiNDAgPCA1MCB5ZWFyIG9sZHMiLA0KICAgIGlmZWxzZShBZ2UgJWluJSA1MDo1OSwgIjUwIDwgNjAgeWVhciBvbGRzIiwNCiAgICBpZmVsc2UoQWdlICVpbiUgNjA6NjksICI2MCA8IDcwIHllYXIgb2xkcyIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDcwOjc5LCAiNzAgPCA4MCB5ZWFyIG9sZHMiLA0KICAgIGlmZWxzZShBZ2UgJWluJSA4MDo4OSwgIjgwIDwgOTAgeWVhciBvbGRzIiwNCiAgICBpZmVsc2UoQWdlICVpbiUgOTA6OTksICI5MCA8IDEwMCB5ZWFyIG9sZHMiLA0KICAgIGlmZWxzZShBZ2UgJWluJSAxMDA6MTA5LCAiMTAwIDwgMTEwIHllYXIgb2xkcyIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDExMDoxMjAsICIxMTAgLSAxMjAgIHllYXIgb2xkcyIsDQogICAgTkEpKSkpKSkpKSkpKSkNCg0KI3NwbGl0dGluZyB6aXBjb2RlIHNhbGFyeSBpbnRvIHJhbmdlcyBmb3IgZWFzeSB2aXN1YWxpemF0aW9uIA0KZGF0YV9jbGVhbmVkIDwtIGRhdGFfY2xlYW5lZCAlPiUNCiAgbXV0YXRlKHppcHNscnlfcmFuZ2UgPSANCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgOTAwMDA6OTkwMDAsICI5MEstOTlLIiwNCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgMTAwMDAwOjE0OTAwMCwgIjEwMEstMTQ5SyIsIA0KICAgIGlmZWxzZSh6aXBjb2RlX3NscnkgJWluJSAxNTAwMDA6MTk5MDAwLCAiMTUwSy0xOTlLIiwNCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgMjAwMDAwOjI0OTAwMCwgIjIwMEstMjQ5SyIsDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDI1MDAwMDoyOTkwMDAsICIyNTBLLTI5OUsiLA0KICAgIGlmZWxzZSh6aXBjb2RlX3NscnkgJWluJSAzMDAwMDA6MzQ5MDAwLCAiMzAwSy0zNDlLIiwNCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgMzUwMDAwOjM5OTAwMCwgIjM1MEstMzk5SyIsDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDQwMDAwMDo0OTkwMDAsICI0MDBLLTQ5OUsiLA0KICAgIGlmZWxzZSh6aXBjb2RlX3NscnkgJWluJSA1MDAwMDA6OTk5MDAwLCAiNTAwSy05OTlLIiwNCiAgICBOQSkpKSkpKSkpKSkNCg0KZ2xpbXBzZShkYXRhX2NsZWFuZWQkemlwc2xyeV9yYW5nZSkNCg0KDQojc2VlaW5nIHdoYXQgd2UgaGF2ZQ0KdGFibGUoZGF0YWNsZWFuaW5nJGFnZV9yYW5nZSkNCiM1MC02MCBpcyB0aGUgbW9zdCBjb21tb24gYWdlIHJhbmdlIA0KDQojUmVtb3ZpbmcgQ29sdW1ucyB0aGF0IHByb3ZpZGUgbm8gYmVuZWZpdCANCg0KZGF0YV9jbGVhbmVkX2NvbHVtbnMgPC0gc3Vic2V0KGRhdGFjbGVhbmluZyxzZWxlY3QgPSAtYyhBc3NpZ25tZW50Lk51bWJlcg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsQXNzaWdubWVudC5oYXMuSGlzdG9yaWNhbC5NbmdyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxTdWZmaXgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuRGF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsQXNzaWdubWVudC5NYW5hZ2VyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxBc3NpZ25tZW50LlJvbGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuVGl0bGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuU3RhdHVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxTdHJhdGVneQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsUHJvZ3Jlc3MuTGV2ZWwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuR3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuQ2F0ZWdvcnkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEZ1bmRpbmcuTWV0aG9kDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxFeHBlY3RlZC5Cb29rLkRhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLFF1YWxpZmljYXRpb24uQW1vdW50DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxFeHBlY3RlZC5Cb29rLkFtb3VudA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsRXhwZWN0ZWQuQm9vay5EYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxIYXJkLkdpZnQuVG90YWwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLFNvZnQuQ3JlZGl0LlRvdGFsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxUb3RhbC5Bc3NpZ25tZW50LkdpZnRzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxOby5vZi5QbGVkZ2VzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxQcm9wb3NhbC4uDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxQcm9wb3NhbC5Ob3Rlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsSEguTGlmZS5IYXJkLkNyZWRpdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsSEguTGlmZS5Tb2Z0LkNyZWRpdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsSEguTGlmZS5TcG91c2UuQ3JlZGl0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxMYXN0LkNvbnRhY3QuQnkuTWFuYWdlcg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsWC4ub2YuQ29udGFjdHMuQnkuTWFuYWdlcikpDQojY2xlYW5pbmcgdXAgemlwIGNvZGVzIHJlbW92aW5nIC00IGFmdGVyIA0KZGF0YV9jbGVhbmVkX2NvbHVtbnMkWmlwIDwtIGdzdWIoZGF0YV9jbGVhbmVkX2NvbHVtbnMkWmlwLCBwYXR0ZXJuPSItLioiLCByZXBsYWNlbWVudCA9ICIiKQ0KDQojYWRkaW5nIHppcCBjb2RlIGRhdGEgYW5kIGNvbHVtbiANCnppcCA8LSByZWFkLmNzdihoZXJlOjpoZXJlKCJmaW5hbF9wcm9qZWN0IiwgIlNhbGFyeV9aaXBjb2RlLmNzdiIpLA0KICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgbmEuc3RyaW5ncyA9ICIiKQ0KDQojYWRkaW5nIHppcCBzYWxhcnkgY29sdW1uDQpkYXRhX2NsZWFuZWRfY29sdW1ucyA8LWRhdGFfY2xlYW5lZF9jb2x1bW5zICU+JQ0KICAgIG11dGF0ZSh6aXBjb2RlX3NscnkgPSBWTE9PS1VQKFppcCwgemlwLCBOQU1FLCBTMTkwMl9DMDNfMDAyRSkpDQoNCiNhZGRpbmcgc2Nob2xhcnNoaXAgZGF0YSAoeS9uKQ0Kc2NobHIgPC0gcmVhZC5jc3YoaGVyZTo6aGVyZSgiZmluYWxfcHJvamVjdCIsICJzY2hvbGFyc2hpcC5jc3YiKSwNCiAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICBzdHJpcC53aGl0ZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSAiIikNCg0KI2FkZGluZyBzY2hvbGFyc2hpcCBjb2x1bW4NCmRhdGFfY2xlYW5lZF9jb2x1bW5zIDwtZGF0YV9jbGVhbmVkX2NvbHVtbnMgJT4lDQogICAgbXV0YXRlKHNjaG9sYXJzaGlwID0gVkxPT0tVUChJRCwgc2NobHIsIElELCBTQ0hPTEFSU0hJUCkpIA0KDQojcmVwbGFjaW5nIE5BIHdpdGggMCANCiBkYXRhX2NsZWFuZWRfY29sdW1ucyRzY2hvbGFyc2hpcCA8LSByZXBsYWNlX25hKGRhdGFfY2xlYW5lZF9jb2x1bW5zJHNjaG9sYXJzaGlwLCcwJykNCiANCiNyZXBsYWNpbmcgWSB3aXRoIDEgDQpkYXRhX2NsZWFuZWRfY29sdW1ucyRzY2hvbGFyc2hpcDwtaWZlbHNlKGRhdGFfY2xlYW5lZF9jb2x1bW5zJHNjaG9sYXJzaGlwPT0iWSIsMSwwKQ0KDQojY2hlY2tpbmcgaG93IG1hbnkgYXJlIE4NCnRhYmxlKGRhdGFfY2xlYW5lZF9jb2x1bW5zJHNjaG9sYXJzaGlwKQ0KDQoNCiNjaGVja2luZyBhbmQgZGVsZXRpbmcgc2Nob2xhcnNoaXAgY29sdW1uIA0KY2xhc3MoZGF0YV9jbGVhbmVkX2NvbHVtbnMkc2NobHJfZmN0KQ0KZGF0YV9jbGVhbmVkX2NvbHVtbnMgPSBzdWJzZXQoZGF0YV9jbGVhbmVkX2NvbHVtbnMsIHNlbGVjdCA9IC1jKHNjaG9sYXJzaGlwKSkNCiAgDQojY2hlY2tpbmcgZm9yIGR1cGxpY2F0ZXMgTiA+MSBpbmRpY2F0ZXMgYSByZWNvcmRzIHZhbHVlcyBhcmUgaW4gdGhlIGZpbGUgdHdpY2UgDQpkYXRhX2NsZWFuZWRfY29sdW1ucyAlPiUgZ3JvdXBfYnkoSUQpICU+JSBjb3VudCgpICU+JSBhcnJhbmdlKGRlc2MobikpDQoNCiNyZW1vdmluZyBkdXBsaWNhdGVkIHJlY29yZHMNCg0KZGF0YV9jbGVhbmVkIDwtIHVuaXF1ZShkYXRhX2NsZWFuZWRfY29sdW1ucykNCg0KI24gPSAxIG5vIElEIHdpdGggbXVsdGlwbGUgcmVjb3JkcyBjbGVhbmVkIG9mIGR1cGVzDQpkYXRhX2NsZWFuZWQgJT4lIGdyb3VwX2J5KElEKSAlPiUgY291bnQoKSAlPiUgYXJyYW5nZShkZXNjKG4pKQ0KDQpgYGANCg0KMWMgQ3JlYXRpbmcgZmFjdG9yIHZhcmlhYmxlIGZvciBzZXggYW5kIG1hcnJpZWQgDQoNCmBgYHtyfQ0KDQpkYXRhX2NsZWFuZWQgPC0gDQogIGRhdGFfY2xlYW5lZCAlPiUgDQogIG11dGF0ZShzZXhfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShTZXgpDQogICkNCg0KDQpkYXRhX2NsZWFuZWQgPC0NCmRhdGFfY2xlYW5lZCAlPiUgDQptdXRhdGUoDQogIHNleF9zaW1wbGUgPSANCiAgICBmY3RfbHVtcF9uKFNleCwgbiA9IDQpDQopDQoNCiNjaGVja2luZyB0byBzZWUgaWYgaXRzIGEgZmFjdG9yDQpjbGFzcyhkYXRhX2NsZWFuZWQkc2V4X2ZjdCkNCg0KI2NoZWNraW5nIGxldmVscw0KbGV2ZWxzKGRhdGFfY2xlYW5lZCRzZXhfc2ltcGxlKQ0KDQojY3JlYXRpbmcgYSB0YWJsZSBhZ2FpbnN0IFNleCBjb2x1bW4gDQp0YWJsZShkYXRhX2NsZWFuZWQkc2V4X2ZjdCwgZGF0YV9jbGVhbmVkJHNleF9zaW1wbGUpDQoNCiNtYWtpbmcgbWFycmllZCBhIGZhY3RvciANCmRhdGFfY2xlYW5lZF9jb2x1bW5zIDwtIA0KICBkYXRhX2NsZWFuZWRfY29sdW1ucyAlPiUgDQogIG11dGF0ZShtYXJyaWVkX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoTWFycmllZCkNCiAgKQ0KDQojY2hlY2tpbmcgdG8gc2VlIGlmIGl0cyBhIGZhY3Rvcg0KY2xhc3MoZGF0YV9jbGVhbmVkJG1hcnJpZWRfZmN0KQ0KDQoNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCg0KDQoNCmBgYA0KDQoxZCAjTWVhbiwgTWVkaWFuLCBhbmQgQ291bnQgb2YgR2l2aW5nIGluIEFnZSBSYW5nZXMgDQoNCmBgYHtyfQ0KDQphZ2VfcmFuZ2VfZ2l2aW5nIDwtIGRhdGFjbGVhbmluZyAlPiUNCiAgZ3JvdXBfYnkoYWdlX3JhbmdlKSAlPiUNCiAgc3VtbWFyaXNlKGF2Z19naXZpbmcgPSBtZWFuKEhILkxpZmV0aW1lLkdpdmluZywgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIG1lZF9naXZpbmcgPSBtZWRpYW4oSEguTGlmZXRpbWUuR2l2aW5nLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgYW1vdW50X29mX3Blb3BsZV9pbl9hZ2VfcmFuZ2UgPSBuKCkpDQoNCg0KDQpgYGANCg0KDQoNCg0KDQojIyBRdWVzdGlvbiAyDQoNCkRvbm9yU2VnbWVudCBBbmFseXNpcw0KDQpgYGB7cn0NCiNncm91cGluZyBieSBkb25vcnNlZ21lbnQgYW5kIGFuYWx5emluZyANCmRhdGFfY2xlYW5lZF9jb2x1bW5zICU+JQ0KICBncm91cF9ieShEb25vci5TZWdtZW50KSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbGVuZ3RoKERvbm9yLlNlZ21lbnQpLA0KICAgICAgICAgICAgbWVhbl90b3RhbF9naXYgPSBtZWFuKEhILkxpZmV0aW1lLkdpdmluZykpICU+JQ0KICBhcnJhbmdlKC1Db3VudCkgJT4lDQogIGZpbHRlcihDb3VudCA+PSAxMDApICU+JQ0KICAjYWRkZWQgc2NhbGVzIHBhY2thZ2UgdG8gaGF2ZSB0aGUgdmFsdWVzIHNob3cgaW4gZG9sbGFyIA0KICBtdXRhdGUobWVhbl90b3RhbF9naXYgPSBkb2xsYXIobWVhbl90b3RhbF9naXYpKSAlPiUNCiAga2FibGUoY29sLm5hbWVzID0gYygiRG9ub3IgU2VnbWVudCIsICJDb3VudCIsICJNZWFuIEhIIExpZmV0aW1lIEdpdmluZyIpLCBhbGlnbj1yZXAoJ2MnLCAzKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiksDQogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYpDQogIA0KDQpgYGANCg0KMmEpIFBsb3R0aW5nIGF2ZXJhZ2UgZ2l2aW5nIGJ5IGFnZSByYW5nZSANCg0KDQpgYGB7cn0NCg0KZ2dwbG90KGFnZV9yYW5nZV9naXZpbmcsIGFlcyhhdmdfZ2l2aW5nLCBhZ2VfcmFuZ2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQ0KDQoNCmBgYA0KDQoNCjJiKSBDb3VudCBvZiBkb25vcnMgYmFzZWQgb24gYWdlIHJhbmdlIChhbm90aGVyIHdheSB0byBsb29rIGF0IGl0KQ0KDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YWNsZWFuaW5nLCANCiAgICAgICBhZXMoYWdlX3JhbmdlKSkgKyANCiAgICAgICBnZW9tX2JhcigpICsgDQogICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3Q9MSkpICsgDQogIGxhYnModGl0bGUgPSAiQ291bnQgb2YgQWdlIFJhbmdlcyIsIHggPSAiIiwgeSA9ICIiKQ0KICANCg0KYGBgDQoNCjJjKSBCb3hwbG90IG9mIHRoZSBBZ2UgUmFuZ2VzIEFnYWluc3QgdGhlIExpZmV0aW1lIEdpdmluZyBBbW91bnRzIHdpdGggYSBsb2cgc2NhbGUgYXBwbGllZCAtIHRoZSByZWFzb24gd2UgYXBwbGllZCBsb2cgc2NhbGUgaXMgdG8gcmVzb2x2ZSBpc3N1ZXMgd2l0aCB2aXN1YWxpemF0aW9ucyB0aGF0IHNrZXcgdG93YXJkcyBsYXJnZSB2YWx1ZXMgaW4gb3VyIGRhdGFzZXQuIA0KDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YWNsZWFuaW5nLCBhZXMoYWdlX3JhbmdlLEhILkxpZmV0aW1lLkdpdmluZyxmaWxsID0gYWdlX3JhbmdlKSkgKyANCiAgZ2VvbV9ib3hwbG90KA0KICBvdXRsaWVyLmNvbG91ciA9ICJyZWQiKSArIA0KICBzY2FsZV95X2xvZzEwKCkgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MSkpDQogIA0KDQpgYGANCg0KMmQpIFNwbGl0dGluZyBieSBhZ2UgYW5kIGdlbmRlciANCg0KDQpgYGB7cn0NCg0KDQojY3JlYXRpbmcgYm94cGxvdHMgDQpkYXRhY2xlYW5pbmcgJT4lIA0KICBmaWx0ZXIoQWdlIDwgMTAwKSAlPiUgI3JlbW92aW5nIHRoZSB3ZWlyZCBvdXRsaWVycyB0aGF0IGFyZSBvdmVyIDEwMCANCiAgZmlsdGVyKFNleCAlaW4lIGMoIk0iLCAiRiIpKSAlPiUNCiAgZ2dwbG90KGFlcyhTZXgsIEFnZSkpICsgDQogIGdlb21fYm94cGxvdCgpICsgDQogIHRoZW1lX2Vjb25vbWlzdCgpICsgDQogIGdndGl0bGUoIkFnZXMgb2YgRG9ub3JzIEJhc2VkIG9uIEdlbmRlciIpICsgDQogIHhsYWIoTlVMTCkgKyB5bGFiKE5VTEwpDQogIA0KICANCiAgDQoNCg0KYGBgDQoNCjJlKSBEaXN0cmlidXRpb24gb2YgcGVvcGxlIGluIHRoZSBzdGF0ZXMgdGhhdCB0aGV5IGxpdmUuDQoNCmBgYHtyfQ0KDQogIGRhdGFjbGVhbmluZyAlPiUNCiAgbXV0YXRlKFN0YXRlID0gaWZlbHNlKFN0YXRlID09ICIgIiwgIk5BIiwgU3RhdGUpKSAlPiUNCiAgZmlsdGVyKFN0YXRlICE9ICJOQSIpICU+JQ0KICBncm91cF9ieShTdGF0ZSkgJT4lDQogIHN1bW1hcmlzZShDb3VudCA9IGxlbmd0aChTdGF0ZSkpICU+JQ0KICBmaWx0ZXIoQ291bnQgPiA4MDApICU+JQ0KICBhcnJhbmdlKC1Db3VudCkgJT4lDQogIGthYmxlKGNvbC5uYW1lcyA9IGMoIkRvbm9yJ3MgU3RhdGUiLCAiQ291bnQiKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJjb25kZW5zZWQiKSwNCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikNCiAgDQogDQogIA0KICANCg0KDQpgYGANCg0KMmYpIExvb2tpbmcgYXQgYWxsIGRvbm9ycyBmaXJzdCBnaWZ0IGFtb3VudC4gNzUlIG1hZGUgYSBmaXJzdCBnaWZ0IG9mIDwxMDAuIA0KDQpgYGB7cn0NCg0KIG5vX25vbl9kb25vcnMgPC0gZGF0YWNsZWFuaW5nICU+JQ0KICBmaWx0ZXIoTGlmZXRpbWUuR2l2aW5nICE9IDApDQogIA0KbmQgPC0gcXVhbnRpbGUobm9fbm9uX2Rvbm9ycyRISC5GaXJzdC5HaWZ0LkFtb3VudCwgcHJvYnMgPSBjKC4yNSwuNTAsLjc1LC45LC45OSksIG5hLnJtID0gVFJVRSkNCg0KbmQgPC0gYXMuZGF0YS5mcmFtZShuZCkNCg0KbmQgJT4lDQogIGthYmxlKGNvbC5uYW1lcyA9ICJRdWFudGlsZSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLA0KICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGKQ0KICANCiAgDQoNCg0KYGBgDQoNCg0KDQojIyBNb2RlbGluZyBmb3IgeW91IA0KDQoNCjNhKSBMaW5lYXIgbW9kZWwgDQoNCmBgYHtyfQ0KI2NvbnZlcnRpbmcgbWFycmllZCBZIGFuZCBOIHRvIDEgYW5kIDAgDQpkYXRhY2xlYW5pbmcgPC0gZGF0YWNsZWFuaW5nICU+JQ0KICAgICAgbXV0YXRlKE1hcnJpZWRfc2ltcGxlID0gaWZlbHNlKE1hcnJpZWQgPT0gIk4iLDAsMSkpDQogDQoNCm1vZDFsbSA8LSBsbSggTWFycmllZF9zaW1wbGUgfiBMaWZldGltZS5HaXZpbmcsDQogICAgICAgICAgIGRhdGEgPSBkYXRhY2xlYW5pbmcpDQoNCnN1bW1hcnkobW9kMWxtKQ0KICANCg0KDQpgYGANCkttZWFucw0KYGBge3J9DQoNCnByZWRfdmFycyA8LSBjKCdtYXJyaWVkX2ZjdCcsICdzZXhfZmN0JykgDQogDQogDQpkYXRhX2NsZWFuZWRfSyA8LSBzZWxlY3QoZGF0YV9jbGVhbmVkLA0KICAgICAgICAgICAgICAgICAgICAgcHJlZF92YXJzLA0KICAgICAgICAgICAgICAgICAgICAgSEguTGlmZXRpbWUuR2l2aW5nKQ0KIA0KI2J1aWxkIGNsdXN0ZXINCmRkX2ttZWFucyA8LSBrbWVhbnMoeCA9IGRhdGFfY2xlYW5lZF9LLCANCiAgICAgICAgICAgICAgICAgICAgY2VudGVycyA9IDUsIA0KICAgICAgICAgICAgICAgICAgICBuc3RhcnQgPSAxMCkNCg0KaXMubnVtZXJpYyhkYXRhX2NsZWFuZWQkSEguTGlmZXRpbWUuR2l2aW5nKQ0KDQpgYGANCg0KDQoNCg0KDQozYSkgDQoNCmBgYHtyfQ0KcCA8LSBkYXRhY2xlYW5pbmcgJT4lDQogIGdncGxvdChhZXMoQWdlKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zPTMwLCBmaWxsID0gImJsdWUiKSArIHRoZW1lX2Vjb25vbWlzdF93aGl0ZSgpICsNCiAgZ2d0aXRsZSgiT3ZlcmFsbCBEb25vciBBZ2UgRGlzdHJpYnV0aW9uIikgKyANCiAgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDUsMTAwLGJ5ID0gMjApKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMjAsMTAwLGJ5ID0gMjApKSArIHhsaW0oYygyMCwxMDApKQ0KDQpnZ3Bsb3RseShwKQ0KICANCnANCg0KZ2dwbG90KGRhdGEgPSBkYXRhY2xlYW5pbmcsIGFlcyh4ID0gQWdlKSkgKyBnZW9tX2hpc3RvZ3JhbShmaWxsID0iYmx1ZSIpKyB4bGltKGMoMjAsMTAwKSkNCg0KICANCg0KDQpgYGANCg==